"""
ReadMe：缺陷数据分析

统计Bug消减计划

"""

import pandas as pd
import ComBase as cb
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
# Set the font to SimHei to support CJK characters
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建饼状图
def draw_pie(file_content):
    # 创建一个PdfPages对象用于写入多个图形
    pdf_pages = PdfPages('E:/个人/个人代码/data/output/Bug信息统计.pdf')
    unique_project_list = file_content.drop_duplicates(subset='项目')['项目'].to_list()
    # print(unique_project_list)
    # 针对每一个项目进行单独处理
    for project in unique_project_list:
        # 过滤后的数据，按照“状态”列的内容进行分类计数汇总
        grouped = file_content[file_content['项目'] == project].groupby('状态')['辅助列'].value_counts()
        # 按循环生成每一个饼状图
        plt.figure(figsize=(10, 10))
        plt.pie(grouped, labels=grouped.index, autopct='%1.1f%%', shadow=False, startangle=90)
        # 生成饼状图的图例
        plt.legend(loc='upper right')
        plt.title(project + '项目缺陷状态信息统计')
        pdf_pages.savefig()
        plt.close()

        # 过滤后的数据，按照“严重程度”列的内容进行分类计数汇总
        grouped = file_content[file_content['项目'] == project].groupby('严重程度')['辅助列'].value_counts()
        # 按循环生成每一个饼状图
        plt.figure(figsize=(10, 10))
        plt.pie(grouped, labels=grouped.index, autopct='%1.1f%%', shadow=False, startangle=90)
        # 生成饼状图的图例
        plt.legend(loc='upper right')
        plt.title(project + '项目缺陷严重程度信息统计')
        pdf_pages.savefig()
        plt.close()

        # bug按“发现版本”分布
        grouped = file_content[file_content['项目'] == project].groupby('发现版本')['辅助列'].value_counts()
        # print(grouped)
        # 按循环生成每一个饼状图
        plt.figure(figsize=(10, 10))
        plt.bar(x=grouped.index.get_level_values(0), height=grouped.values.flatten(), width=0.5)
        # 为每个柱子添加标签
        for i, v in enumerate(grouped.values):
            plt.text(i, v, "{:.1f}".format(v), ha='center', va='bottom', fontsize=6)
        # 生成饼状图的图例
        plt.xticks(fontsize=10, rotation=90)
        plt.xlabel('发现版本')
        plt.ylabel('bug数量')
        plt.tight_layout()
        plt.title(project + '项目缺陷按版本分布信息统计')
        pdf_pages.savefig()
        plt.close()

        # 按bug的“引入阶段”分布
        grouped = file_content[file_content['项目'] == project].groupby('引入阶段')['辅助列'].value_counts()
        # 按循环生成每一个饼状图
        plt.figure(figsize=(10, 10))
        plt.pie(grouped, labels=grouped.index, autopct='%1.1f%%', shadow=False, startangle=90)
        # 生成饼状图的图例
        plt.legend(loc='upper right')
        plt.title(project + '项目缺陷按引入阶段分布信息统计')
        pdf_pages.savefig()
        plt.close()

        # 按bug的“创建于”分布
        # 将创建于的时间格式转换为年月日
        file_content['创建于'] = pd.to_datetime(file_content['创建于']).dt.strftime('%Y-%m-%d')
        grouped = file_content[file_content['项目'] == project].groupby('创建于')['辅助列'].value_counts()
        # 按循环生成每一个饼状图
        plt.figure(figsize=(15, 10))
        plt.bar(x=grouped.index.get_level_values(0), height=grouped.values.flatten(), width=0.3)
        # 为每个柱子添加标签
        for i, v in enumerate(grouped.values):
            plt.text(i, v, "{:.1f}".format(v), ha='center', va='bottom', fontsize=6)
        plt.xticks(fontsize=10, rotation=90)
        plt.xlabel('发现日期')
        plt.ylabel('bug数量')
        plt.tight_layout()
        plt.title(project + '项目缺陷按日期分布信息统计')
        pdf_pages.savefig()
        plt.close()

    # 最后关闭PDF文件
    pdf_pages.close()

# 创建线形图
def draw_line(file_content):
    # 创建一个PdfPages对象用于写入多个图形
    pdf_pages = PdfPages('E:/个人/个人代码/data/output/项目Bug趋势表.pdf')

    # 1.分别将创建和关闭日期转换成周
    # 增加“创建周”列，内容为创建日期所在周
    file_content['创建周'] = pd.to_datetime(file_content['创建日期']).dt.isocalendar().week
    # 增加“关闭周”列，内容为关闭日期所在周
    file_content['关闭周'] = pd.to_datetime(file_content['关闭日期']).dt.isocalendar().week
    file_content['辅助列'] = "1"

    # 2.按项目分别统计每个周的bug新增和关闭数量
    unique_project_list = file_content.drop_duplicates(subset='所属项目')['所属项目'].to_list()
    # 去掉unique_project_list中的空值
    unique_project_list = [x for x in unique_project_list if str(x) != 'nan']
    print(unique_project_list)
    for project in unique_project_list:
        grouped = file_content[file_content['所属项目'] == project].groupby(['所属项目','创建周'])['辅助列'].count().reset_index(name='新增数量')
        # 将grouped进行行列转换
        grouped = grouped.pivot(index='所属项目', columns='创建周', values='新增数量')
        print(grouped)

        # 3.绘制折线图
        plt.figure(figsize=(15, 10))
        plt.plot(grouped.columns, grouped.values.flatten())
        plt.xticks(grouped.columns)
        plt.xlabel('周')
        plt.ylabel('新增数量')
        # 为每个点添加标签
        for i, v in enumerate(grouped.values.flatten()):
            plt.text(i, v, "{:.1f}".format(v), ha='center', va='bottom', fontsize=6)
        plt.title(str(project) + '项目每周新增bug数量统计')
        plt.grid()
        pdf_pages.savefig()
        plt.close()

    # 最后关闭PDF文件
    pdf_pages.close()

# 统计bug生存周期
def calBugLiftCycle(file_content):
    # 将“Bug状态”不等于“已关闭”的数据，关闭日期默认更新成当前日期
    file_content.loc[file_content['Bug状态'] != '已关闭', '关闭日期'] = pd.to_datetime('today')

    # 新增“生存周期”列，内容为两个日期相减得到天数 +1
    file_content['生存周期'] = (pd.to_datetime(file_content['关闭日期']) - pd.to_datetime(file_content['创建日期'])).dt.days + 1
    # 将closed_bugs导出为Excel文件
    file_content.to_excel('E:/个人/个人代码/data/output/已登记bug生存周期统计表.xlsx', index=True)
    # 将导出Excel文件的sheet页名称修改为“详细数据”
    with pd.ExcelWriter('E:/个人/个人代码/data/output/已登记bug生存周期统计表.xlsx', engine='openpyxl') as writer:
        file_content.to_excel(writer, sheet_name='详细数据', index=False)

    # 按照“生存周期”列的内容进行分类计数汇总
    file_content_grouped = file_content.groupby('生存周期')['生存周期'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_grouped = file_content_grouped.reset_index(name='数量')
    # 增加一列“占比”，计算公式为数量/总数量
    file_content_grouped['占比%'] = file_content_grouped['数量'] / file_content_grouped['数量'].sum()
    # 占比列的内容保留三位小数
    file_content_grouped['占比%'] = file_content_grouped['占比%'].apply(lambda x: format(x, '.3%'))
    # 将“占比”列的格式设置成数字
    file_content_grouped['占比%'] = pd.to_numeric(file_content_grouped['占比%'].str.strip('%'))
    # 将closed_bugs_grouped导出到Excel文档中新增sheet页
    with pd.ExcelWriter('E:/个人/个人代码/data/output/已登记bug生存周期统计表.xlsx', engine='openpyxl', mode='a') as writer:
        file_content_grouped.to_excel(writer, sheet_name='生存周期统计', index=False)

    # 将“Bug标题”包含“外部”两个字的内容刷选出来
    out_bugs = file_content[file_content['Bug标题'].str.contains('外部')]
    # 外部bug的生存周期按照解决时间减去创建时间得到
    out_bugs.loc[file_content['Bug状态'] != '已解决', '解决日期'] = pd.to_datetime('today')
    out_bugs['外部生存周期'] = (pd.to_datetime(out_bugs['解决日期']) - pd.to_datetime(out_bugs['创建日期'])).dt.days + 1
    out_bugs_grouped = out_bugs.groupby('外部生存周期')['外部生存周期'].count()
    out_bugs_grouped = out_bugs_grouped.reset_index(name='数量')
    # 增加一列“占比”，计算公式为数量/总数量，占比列的内容保留三位小数
    out_bugs_grouped['占比%'] = out_bugs_grouped['数量'] / out_bugs_grouped['数量'].sum()
    out_bugs_grouped['占比%'] = out_bugs_grouped['占比%'].apply(lambda x: format(x, '.3%'))
    # 将“占比”列的格式设置成数字
    out_bugs_grouped['占比%'] = pd.to_numeric(out_bugs_grouped['占比%'].str.strip('%'))

    with pd.ExcelWriter('E:/个人/个人代码/data/output/已登记bug生存周期统计表.xlsx', engine='openpyxl', mode='a') as writer:
        out_bugs_grouped.to_excel(writer, sheet_name='外部bug生存周期统计', index=False)

# 统计每周新增和关闭的bug数量
def calBugAddAndClose(file_content):
    # 新增“新增周”列
    file_content['新增周'] = pd.to_datetime(file_content['创建日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content['创建日期']).dt.isocalendar().week.astype(str)
    # 按照“新增周”列的内容进行分类计数汇总
    file_content_add_grouped = file_content.groupby('新增周')['新增周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_add_grouped = file_content_add_grouped.reset_index(name='新增数量')
    # print(file_content_add_grouped)

    # 导出数据到Excel
    file_content_add_grouped.to_excel('E:/个人/个人代码/data/output/每周新增bug统计.xlsx', index=False)

    # 筛选状态为“已关闭”的数据
    file_content_close = file_content[file_content['Bug状态'] == '已关闭']
    # 新增“关闭周”列
    file_content_close['关闭周'] = pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().week.astype(str)
    # 按照“关闭周”列的内容进行分类计数汇总
    file_content_close_grouped = file_content_close.groupby('关闭周')['关闭周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_close_grouped = file_content_close_grouped.reset_index(name='关闭数量')
    # print(file_content_close_grouped)

    # 导出数据到Excel
    file_content_close_grouped.to_excel('E:/个人/个人代码/data/output/每周关闭bug统计.xlsx', index=False)

# 统计每周新增和关闭的bug数量
def calInnerBugClose(file_content):
    # 新增“新增周”列
    file_content['新增周'] = pd.to_datetime(file_content['创建日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content['创建日期']).dt.isocalendar().week.astype(str)
    # 按照“新增周”列的内容进行分类计数汇总
    file_content_add_grouped = file_content.groupby('新增周')['新增周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_add_grouped = file_content_add_grouped.reset_index(name='新增数量')
    # print(file_content_add_grouped)

    # 导出数据到Excel
    file_content_add_grouped.to_excel('E:/个人/个人代码/data/output/内部bug每周新增bug统计.xlsx', index=False)

    # 筛选状态为“已关闭”的数据
    file_content_close = file_content[file_content['Bug状态'] == '已关闭']
    # 新增“关闭周”列
    file_content_close['关闭周'] = pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().week.astype(str)
    # 按照“关闭周”列的内容进行分类计数汇总
    file_content_close_grouped = file_content_close.groupby('关闭周')['关闭周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_close_grouped = file_content_close_grouped.reset_index(name='关闭数量')
    # print(file_content_close_grouped)

    # 导出数据到Excel
    file_content_close_grouped.to_excel('E:/个人/个人代码/data/output/内部bug每周关闭bug统计.xlsx', index=False)

# 统计每周解决的外部bug数量
def calOuterBugClose(file_content):
    # 新增“新增周”列
    file_content['新增周'] = pd.to_datetime(file_content['创建日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content['创建日期']).dt.isocalendar().week.astype(str)
    # 按照“新增周”列的内容进行分类计数汇总
    file_content_add_grouped = file_content.groupby('新增周')['新增周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_add_grouped = file_content_add_grouped.reset_index(name='新增数量')
    # print(file_content_add_grouped)
    # 导出数据到Excel
    file_content_add_grouped.to_excel('E:/个人/个人代码/data/output/外部bug每周新增统计.xlsx', index=False)

    # 筛选状态为“已关闭”和“已解决”的数据
    file_content_close = file_content[(file_content['Bug状态'] == '已关闭') | (file_content['Bug状态'] == '已解决')]
    # 新增“关闭周”列
    # 如果是关闭状态，关闭日期就是关闭日期，如果是解决状态，关闭日期就是解决日期
    file_content_close.loc[file_content_close['Bug状态'] == '已解决', '关闭日期'] = file_content_close['解决日期']
    file_content_close['关闭周'] = pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().year.astype(
        str) + "W" + pd.to_datetime(file_content_close['关闭日期']).dt.isocalendar().week.astype(str)

    # 按照“关闭周”列的内容进行分类计数汇总
    file_content_close_grouped = file_content_close.groupby('关闭周')['关闭周'].count()
    # 将closed_bugs_grouped进行换转列
    file_content_close_grouped = file_content_close_grouped.reset_index(name='关闭数量')
    # print(file_content_close_grouped)
    # 导出数据到Excel
    file_content_close_grouped.to_excel('E:/个人/个人代码/data/output/外部bug每周关闭统计.xlsx', index=False)

# 定义数据文件的路径（禅道的bug数据）
path = 'E:/个人/个人代码/data/bug/'

# 获取数据
file_content = cb.get_date(path)

# 统计全部的数据
calBugAddAndClose(file_content)

# 将“Bug标题”包含“外部”两个字的内容刷选出来
# 只统计外部bug（即客户Coding上的Bug）
file_content_out_bugs = file_content[file_content['Bug标题'].str.contains('外部')]
calOuterBugClose(file_content_out_bugs)

# 将“Bug标题”不包含“外部”两个字的内容刷选出来
# 只统计内部bug（即公司内部测试发现的Bug）
file_content_in_bugs = file_content[~file_content['Bug标题'].str.contains('外部')]
calInnerBugClose(file_content_in_bugs)